let canvas = document.getElementById("cas");
let ctx = canvas.getContext('2d');
/**
 * 全局变量
 * mcl，摩擦力；ballRadius，球半径；t0，初始时刻；dotline,虚线；tbw，桌边宽度；
 * itIsMyTurn,击球权；balls[],桌上所有球；judgeCtrl,裁判标签；agentCtrl,机器人标签；players[],球员；
 */
let mcl = 3 , collarg = 0.8 , ballRadius = 15, t0 = 0 , balls=[] , tbw = 32 , animateStop = true , powAnimation = false;
let itIsRedTurn = 0 ,judgeCtrl = 0 ,agentCtrl = 0 ,players = [];
let myBallInHoled = 0;
let dotline;
pxpm = canvas.width/20;

//主程序，运行即加载
window.onload = function(){
    let myBall = new Ball(202 , canvas.height/2 , true ,0);
    //balls[0]:白球,color=0
    balls.push(myBall);
    //balls[1-7]:黄球,color=2
    //balls[8]:黑球,color=1
    //balls[9-15]:红球,color=3
    let count=1;
    for(let i=0;i<6;i++) {
        for (let j = 0; j < i; j++) {
            let other;
            if (count < 8) {
                other = new Ball(520 + i * (ballRadius - 2) * 2, (canvas.height - i * 2 * ballRadius) / 2 + ballRadius + 2 * ballRadius * j, false, 2);
            } else if (count === 8) {
                other = new Ball(520 + i * (ballRadius - 2) * 2, (canvas.height - i * 2 * ballRadius) / 2 + ballRadius + 2 * ballRadius * j, false, 1);
            } else {
                other = new Ball(520 + i * (ballRadius - 2) * 2, (canvas.height - i * 2 * ballRadius) / 2 + ballRadius + 2 * ballRadius * j, false, 3);
            }
            balls.push(other);
            count++;
        }
    }
    //两个球员,players[0]的目标球定为黄球,是选手,players[1]的目标球定为红球，是Agent;
    players.push(new player(2));
    players.push(new Agent(3));
    //初始化t0
    t0 = new Date();
    dotline = new dotLine(0,0,0,0);

    animateStop = false;
    animate();
};

//touchstart事件，触摸触发，嵌套touchmove和touchend
// canvas.addEventListener("touchstart" , function(){
//     let stop = false;
//     balls.foreach(function(){
//         if(this.moving && !this.inhole)
//             stop = true;
//     });
//     //只要桌面上还有运动的球，就不能进行击打
//     if(stop) return;
//
//     //力度条的显示
//     document.querySelector(".shotPower").style.display = "block";
//     document.querySelector(".shotPower").style.top = balls[0].y-60 + "px";
//     document.querySelector(".shotPower").style.left = balls[0].x-40 +"px";
//     document.getElementById("pow").className = "animate";
//
//     let touch = event.targetTouches[0];
//     let x = touch.pageX + document.body.scrollLeft + document.documentElement.scrollLeft - document.querySelector(".view").offsetLeft;
//     let y = touch.pageY + document.body.scrollTop + document.documentElement.scrollTop - document.querySelector(".view").offsetTop;
//     dotline.display = true;
//     dotline.x0 = balls[0].x;
//     dotline.y0 = balls[0].y;
//     dotline.x1 = x;
//     dotline.y1 = y;
//     //touchend事件，手指从屏幕离开触发
//     window.addEventListener("touchend" , muHandle , false);
//     //touchmove事件，手指在屏幕上滑动时，连续触发
//     window.addEventListener("touchmove" , mmHandle , false);
//     //鼠标滑动时给dotline刷新值
//     function mmHandle(){
//         //取消默认HTML事件
//         event.preventDefault();
//
//         let touch = event.targetTouches[0];
//         let x = touch.pageX + document.body.scrollLeft + document.documentElement.scrollLeft - document.querySelector(".view").offsetLeft;
//         let y = touch.pageY + document.body.scrollTop + document.documentElement.scrollTop - document.querySelector(".view").offsetTop;
//         dotline.x1 = x;
//         dotline.y1 = y;
//     }
//     //鼠标松开时击球，获取白球速度和角度
//     function muHandle(){
//         let x = touch.pageX + document.body.scrollLeft + document.documentElement.scrollLeft - document.querySelector(".view").offsetLeft;
//         let y = touch.pageY + document.body.scrollTop + document.documentElement.scrollTop - document.querySelector(".view").offsetTop;
//         //计算击球角度angle
//         let angle = Math.atan((y - balls[0].y)/(x - balls[0].x));
//         //计算出球速度v
//         let h = document.getElementById("pow").offsetHeight/document.getElementById("powbar").offsetHeight;
//         let v = 60*h;
//         document.getElementById("pow").style.height = h*100+"%";
//         //分解v为vx和vy
//         balls[0].vx = x - balls[0].x>0 ? v*Math.abs(Math.cos(angle)) : -v*Math.abs(Math.cos(angle));
//         balls[0].vy = y - balls[0].y>0 ? v*Math.abs(Math.sin(angle)) : -v*Math.abs(Math.sin(angle));
//
//         document.getElementById("pow").className = "";
//
//         window.removeEventListener("touchend" , muHandle , false);
//         window.removeEventListener("touchmove" , muHandle , false);
//         dotline.display = false;
//         document.querySelector(".shotPower").style.display = "none";
//     }
// },false);

//mousedown,mousemove,mouseup;与touch事件作用相同
canvas.addEventListener("mousedown" , function(){
    //点击事件触发时进行静止检测，只要桌面上的球没有全都静止，就不能开始下一轮击球
    let stop = true;
    balls.foreach(function(){
        if(this.moving && !this.inhole) stop = false;
    });
    if(!stop || judgeCtrl!==0 || itIsRedTurn){
        return;
    }
    document.querySelector(".shotPower").style.display = "block";
    document.querySelector(".shotPower").style.top = balls[0].y-60 + "px";
    document.querySelector(".shotPower").style.left = balls[0].x-40 +"px";
    document.getElementById("pow").className = "animate";
    var x = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft - document.querySelector(".view").offsetLeft;
    var y = event.clientY + document.body.scrollTop + document.documentElement.scrollTop - document.querySelector(".view").offsetTop;
    dotline.display = true;
    dotline.x0 = balls[0].x;
    dotline.y0 = balls[0].y;
    dotline.x1 = x;
    dotline.y1 = y;

    window.addEventListener("mouseup" , muHandle , false);
    window.addEventListener("mousemove" , mmHandle , false);

    function mmHandle(){
        var x = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft - document.querySelector(".view").offsetLeft;
        var y = event.clientY + document.body.scrollTop + document.documentElement.scrollTop - document.querySelector(".view").offsetTop;
        dotline.x1 = x;
        dotline.y1 = y;
    }
    function muHandle(){
        var x = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft - document.querySelector(".view").offsetLeft;
        var y = event.clientY + document.body.scrollTop + document.documentElement.scrollTop - document.querySelector(".view").offsetTop;

        var angle = Math.atan((y - balls[0].y)/(x - balls[0].x));
        var h = document.getElementById("pow").offsetHeight/document.getElementById("powbar").offsetHeight;
        var v = 60*h;
        document.getElementById("pow").style.height = h*100+"%";

        balls[0].vx = x - balls[0].x>0 ? v*Math.abs(Math.cos(angle)) : -v*Math.abs(Math.cos(angle));
        balls[0].vy = y - balls[0].y>0 ? v*Math.abs(Math.sin(angle)) : -v*Math.abs(Math.sin(angle));
        //即刻触发moving变化
        balls[0].moving = true;

        document.getElementById("pow").className = "";

        window.removeEventListener("mouseup" , muHandle , false);
        window.removeEventListener("mousemove" , muHandle , false);
        dotline.display = false;
        document.querySelector(".shotPower").style.display = "none";
        //judgeCtrl解决开局判定的问题
        judgeCtrl++;
    }
},false);

//动画渲染
function animate(){
    //动画静止判定;
    if(!dotline.display){
        let stop = true;
        balls.foreach(function(){
            if(this.moving && !this.inhole ) stop = false;
        });
        if(stop) {
            if (judgeCtrl){
                //TODO judgement
                //alert("test judgement");
                judgement();
                agentCtrl=itIsRedTurn;

                judgeCtrl=0;
            }
            if (agentCtrl){
                players[1]._youKnowNothingAtAll();
                judgeCtrl++;
                //裁判和agent的进场时间不计入动画循环;
                t0 = new Date();
            }
        }
    }

    //-------------------
    ctx.clearRect(0,0,canvas.width,canvas.height);
    let t1 = new Date();
    let t = (t1 - t0)/1000;

    collision(t);
    balls.foreach(function(){
        if(!this.inhole) this._run(t);
    });

    if(dotline.display){
        dotline.x0 = balls[0].x;
        dotline.y0 = balls[0].y;
        dotline._paint();
    }

    t0 = t1;
    //requestAnimationFrame降级,请求动画帧,回调函数:animate
    if(!animateStop){
        if("requestAnimationFrame" in window){
            requestAnimationFrame(animate);
        }
        else if("webkitRequestAnimationFrame" in window){
            webkitRequestAnimationFrame(animate);
        }
        else if("msRequestAnimationFrame" in window){
            msRequestAnimationFrame(animate);
        }
        else if("mozRequestAnimationFrame" in window){
            mozRequestAnimationFrame(animate);
        }
        else {
            setTimeout(animate , 16);
        }
    }
}

//碰撞检测，并计算碰撞后的速度，并修正;
//非对心碰撞时,由于帧延迟显示,冲量方向计算错误;
function collision(t){
    for (let i = 0; i < balls.length; i++) {
        for (let j = 0; j < balls.length; j++) {
            let b1 = balls[i], b2 = balls[j];
            //相异两球，不在球袋中
            if (b1 !== b2 && !b1.inhole && !b2.inhole) {
                //实际球心距离rc
                let rc = Math.sqrt(Math.pow(b1.x - b2.x, 2) + Math.pow(b1.y - b2.y, 2));
                if (Math.ceil(rc) < (b1.radius + b2.radius)) {
                    if (!b1.moving && !b2.moving) return;

                    //from here
                    let x1 = b1.oldx, y1 = b1.oldy, v1x = (b1.oldvx + b1.vx) / 2, v1y = (b1.oldvy + b1.vy) / 2,
                        x2 = b2.oldx, y2 = b2.oldy, v2x = (b2.oldvx + b2.vx) / 2, v2y = (b2.oldvy + b2.vy) / 2;
                    let a = Math.pow(v1x - v2x, 2) + Math.pow(v1y - v2y, 2),
                        b = 2 * ((x2 - x1) * (v2x - v1x) + (y2 - y1) * (v2y - v1y)),
                        c = Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2) - 4 * ballRadius * ballRadius;
                    // 准确的碰撞时刻deltaT,(x1t,y1t),(x2t,y2t)表示碰撞发生时两球准确的圆心坐标;
                    let deltaT = (-b - Math.sqrt(Math.abs(b * b - 4 * a * c))) / (2 * a);
                    let x1t = x1 + v1x * deltaT, y1t = y1 + v1y * deltaT,
                        x2t = x2 + v2x * deltaT, y2t = y2 + v2y * deltaT;
                    let rct = Math.sqrt(Math.pow(x1t - x2t, 2) + Math.pow(y1t - y2t, 2));

                    let ax = ((v1x - v2x) * Math.pow((x1t - x2t), 2) + (v1y - v2y) * (x1t - x2t) * (y1t - y2t)) / Math.pow(rct, 2),
                        ay = ((v1y - v2y) * Math.pow((y1t - y2t), 2) + (v1x - v2x) * (x1t - x2t) * (y1t - y2t)) / Math.pow(rct, 2);

                    let lt = Math.abs(t - deltaT);
                    b1.vx = v1x - ax;
                    b1.vy = v1y - ay;
                    b2.vx = v2x + ax;
                    b2.vy = v2y + ay;

                    b1.oldvx = b1.vx;
                    b1.oldvy = b1.vy;
                    b2.oldvx = b2.vx;
                    b2.oldvy = b2.vy;

                    b1.x = x1t + b1.vx * lt;
                    b1.y = y1t + b1.vy * lt;
                    b2.x = x2t + b2.vx * lt;
                    b2.y = y2t + b2.vy * lt;

                    b1.oldx = x1t;
                    b1.oldy = y1t;
                    b2.oldx = x2t;
                    b2.oldy = y2t;
                    // //根据动能守恒和动量守恒速度增量
                    // let ax = ((b1.vx - b2.vx)*Math.pow((b1.x - b2.x) , 2) + (b1.vy - b2.vy)*(b1.x - b2.x)*(b1.y - b2.y))/Math.pow(rc , 2);
                    // let ay = ((b1.vy - b2.vy)*Math.pow((b1.y - b2.y) , 2) + (b1.vx - b2.vx)*(b1.x - b2.x)*(b1.y - b2.y))/Math.pow(rc , 2);
                    //
                    // b1.vx = b1.vx-ax;
                    // b1.vy = b1.vy-ay;
                    // b2.vx = b2.vx+ax;
                    // b2.vy = b2.vy+ay;
                    //
                    // //修复碰撞后重叠的部分，防止粘连(如果不修复，下一帧可能还是检测到碰撞就离谱了)
                    // //cLength是圆心偏移距离,cx/clength = (x1-x2)/rc;
                    // let cLength = ((b1.radius+b2.radius)-rc)/2;
                    // let cx = cLength * (b1.x-b2.x)/rc;
                    // let cy = cLength * (b1.y-b2.y)/rc;
                    // b1.x = b1.x+cx;
                    // b1.y = b1.y+cy;
                    // b2.x = b2.x-cx;
                    // b2.y = b2.y-cy;
                }
            }
        }
    if (!balls[i].inhole){
        borderCollision(balls[i]);
    }
    }
}

//进球和边界判定;
function borderCollision(b) {
    //6个球袋,根据坐标判定进袋
    if((b.x<50 && b.y<50) || (b.x>375 && b.x<425 && b.y<50) || (b.x > 750 && b.y<50) ||
        (b.x<50 && b.y>494) || (b.x>375 && b.x<425 && b.y>494) || (b.x > 750 && b.y>494)){
        b.inhole = true;
        //白球进袋，返回开球位置
        if(b.ismine){
            myBallInHoled++;
            let that = b;
            //TODO 白球回到起点，被目标球击中怎么处理，起点处复位时已经有球存在会重叠
            setTimeout(function(){
                that.x = 202;
                that.y = canvas.height/2;
                that.vx = 0;
                that.vy = 0;
                that.inhole = false;
            } , 500);

        }else {
            document.getElementById("shotNum").innerHTML = parseInt(document.getElementById("shotNum").innerHTML)+1;
        }
    }
    else {
        //边界碰撞,不作减速处理;
        if (b.x < (ballRadius+tbw)){
            b.x = 2*(tbw+ballRadius)-b.x;
            b.derectionX = !b.derectionX;
            b.vx = -0.6*b.vx;
            b.vy = 0.6*b.vy;
        }
        if (b.x > (canvas.width-ballRadius-tbw)){
            b.x = 2*(canvas.width-ballRadius-tbw)-b.x;
            b.derectionX = !b.derectionX;
            b.vx = -0.6*b.vx;
            b.vy = 0.6*b.vy;
        }
        if (b.y < (ballRadius+tbw)){
            b.y = 2*(ballRadius+tbw)-b.y;
            b.derectionY = !b.derectionY;
            b.vy = -0.6*b.vy;
            b.vx = 0.6*b.vx;
        }
        if (b.y > (canvas.height-ballRadius-tbw)){
            b.y = 2*(canvas.height-ballRadius-tbw)-b.y;
            b.derectionY = !b.derectionY;
            b.vy = -0.6*b.vy;
            b.vx = 0.6*b.vx;
        }
    }
    b._paint();
}
//交换击球权;
function changeTurn() {
    if (itIsRedTurn){
        itIsRedTurn = 0;
        alert("FuHua:黄色方击球");
        // alert("Kiana:芽衣只能是我的，看好吧!");
    }else {
        itIsRedTurn = 1;
        alert("FuHua:红色方击球");
        // alert("Bronya:木大木大");
    }
}

//击球结束，违规和胜负判定
function judgement(){
    let player = players[itIsRedTurn];
    //黑球进袋?
    if (balls[8].inhole){
        if (player.targetBall === 1){
            if (player._violate()){
                //黑球是目标球，进袋同时犯规，判负
                alert("很遗憾，你输了");
                if (itIsRedTurn){
                    alert("Bronya:没想到，功亏一篑……");
                }else {
                    alert("Kiana:啊啊啊！这不算！这不算！！");
                }
                //TODO 结束处理
            }else {
                //黑球是目标球，无犯规进袋，胜利
                alert("恭喜获胜，比赛结束");
                if (itIsRedTurn){
                    alert("Bronya:再见了Kiana，芽衣姐姐已经是我的形状了");
                }else {
                    alert("Kiana:哈哈！本小姐天下无敌！芽衣！芽衣！芽衣！");
                }
            }
        }else {
            //黑球不是目标球，被打进袋，判负
            alert("啊这……你输了，比赛结束");
            if (itIsRedTurn){
                alert("Kiana:哼哼！既然你放弃了，那芽衣就是我一个人的了！");
            }else {
                alert("Bronya:Kiana太蠢了，果然芽衣姐姐只能和我在一起");
            }
        }
    }else if (player._violate()){
        //目标球是黑球，违规计数无效
        //TODO 自由击球
       if (player.targetBall === 1){
           changeTurn();
       }else {
           //目标球不是黑球时，三次违规输局
           if (player.violation === 2){
               alert("FuHua:请不要再胡闹了，你输了，比赛结束");
               if (itIsRedTurn){
                   alert("Bronya:没想到竟会这样结束……");
               }else {
                   alert("Kiana:我不是故意的，芽衣对不起……");
               }
           }else {
               player.violation++;
               changeTurn();
           }
       }
    }else {
        //没有违规，则连续违规次数清零
        player.violation = 0;
        if (player._ballIn()){
            alert("加油！继续！");
        }else{
            changeTurn();
        }
    }

    if (!player.ballNums){
        //如果目标球已全进袋，则黑球为目标球
        player._changeTarget();
    }

    // 裁判会对己方进球进行统计,也要对对方球数统计,防止我误进的对方目标球算作他进的;
    players[0]._count();
    players[1]._count();


    myBallInHoled = 0;
}
/**
 * 定义虚线dotline
 * @param x0 白球位置x
 * @param y0 白球位置y
 * @param x1 目标位置x
 * @param y1 目标位置y
 */
let dotLine = function(x0,y0,x1,y1){
    this.x0 = x0;
    this.y0 = y0;
    this.x1 = x1;
    this.y1 = y1;
    this.dotlength = 3;
    this.display = false;
};
dotLine.prototype = {
    constructor:dotLine,
    _ready:function(){
        this.length = Math.sqrt(Math.pow(this.y1 - this.y0 , 2)+Math.pow(this.x1 - this.x0 , 2));
        this.dotNum = Math.ceil(this.length/this.dotlength);
    },
    _paint:function(){
        this._ready();
        xadd = this.dotlength * (this.x1 - this.x0) / this.length;
        yadd = this.dotlength*(this.y1 - this.y0)/this.length;
        ctx.save();
        ctx.beginPath();
        for(let i=1;i<=this.dotNum;i++){
            if(i%2!==0){
                ctx.moveTo(this.x0+(i-1)*xadd , this.y0+(i-1)*yadd);
                ctx.lineTo(this.x0+i*xadd , this.y0+i*yadd);
            }
        }
        ctx.strokeStyle = "#FFF";
        ctx.stroke();
        ctx.beginPath();
        ctx.arc(this.x1 , this.y1 , ballRadius-2 , 0 , 2*Math.PI);
        ctx.stroke();
        ctx.restore();
    }
};

/**
 * 定义Ball,oldx,oldy表示上一帧的位置
 * @param x
 * @param y
 * @param isMine 为真表示是白球
 * @param color
 * @constructor
 */
let Ball = function(x , y , isMine , color ){
    this.color = color;
    this.x = x;
    this.y = y;
    this.ismine = isMine;
    this.oldx = x;
    this.oldy = y;
    this.vx = 0;
    this.vy = 0;
    this.oldvx = 0;
    this.oldvy = 0;
    this.radius = ballRadius;
    this.inhole = false;
    this.angle = 0;
    this.moving = true;
};
/**
 * Ball.prototype向Ball对象添加属性和方法，包含构造Ball，_paint绘制球体，_run
 */
Ball.prototype = {
    constructor:Ball,
    //根据color渲染
    _paint:function(){
        let b;
        if (this.color===0){
            b = document.getElementById("wb");
        }else if (this.color===1){
            b = document.getElementById("bb");
        }else if (this.color===2){
            b = document.getElementById("yb");
        }else {
            b = document.getElementById("rb");
        }
        if (b.complete){
            ctx.drawImage(b , this.x-this.radius , this.y-this.radius , 2*this.radius , 2*this.radius);
        } else {
            b.onload = function () {
                ctx.drawImage(b, this.x-this.radius, this.y-this.radius , 2*this.radius , 2*this.radius);
            }
        }
    },
    _run:function(t){
        this.oldx = this.x;
        this.oldy = this.y;
        this.oldvx = this.vx;
        this.oldvy = this.vy;
        //速度衰减;
        // this.vx = Math.abs(this.vx)<0.01? 0 : (this.vx>0? this.vx-mcl*t : this.vx+mcl*t);
        // this.vy = Math.abs(this.vy)<0.01? 0 : (this.vy>0? this.vy-mcl*t : this.vy+mcl*t);
        this.angle = Math.abs(Math.atan(this.vy/this.vx));
        if (this.vx !== 0){
            this.vx = this.vx>0? this.vx-mcl*t*Math.cos(this.angle) : this.vx+mcl*t*Math.cos(this.angle);
            //运动静止判定:速度衰减导致异号;
            if (this.oldvx>0&&this.vx<0 || this.oldvx<0&&this.vx>0){
            // if (Math.abs(this.vx)<0.1){
                this.vx = 0;
            }
        }
        if (this.vy !== 0){
            this.vy = this.vy>0? this.vy-mcl*t*Math.sin(this.angle) : this.vy+mcl*t*Math.sin(this.angle);
            if (this.oldvy>0&&this.vy<0 || this.oldvy<0&&this.vy>0){
            // if (Math.abs(this.vy)<0.1){
                this.vy = 0;
            }
        }


        //为下一帧的(x,y)赋值
        this.x += t * (this.vx+this.oldvx) /2* pxpm;
        this.y += t * (this.vy+this.oldvy) /2* pxpm;


        this.moving = !(this.vx === 0 && this.vy === 0);
        // this.moving = !(Math.abs(this.vx) < 0.01 && Math.abs(this.vy) < 0.01);
    }
};

/**
 * 玩家player，_count()统计桌上剩余球个数，_changeTarget改变目标球为黑球
 */
let player = function (targetColor) {
    //目标球颜色
    this.targetBall = targetColor;
    //目标球个数
    this.ballNums = 7;
    //违规次数
    this.violation = 0;
    //上轮m目标球数
    this.oldBallNums = 7;
};
    player.prototype = {
        constructor:player,
        //统计己方目标球个数
        _count:function () {
            this.oldBallNums = this.ballNums;
            this.ballNums = 0;
            for (let i = 0; i < balls.length; i++) {
                if (!balls[i].inhole && balls[i].color===this.targetBall){
                    this.ballNums++;
                }
            }
        },

        _changeTarget:function () {
            this.targetBall=1;
        },

        //违规判定，白球进袋，不碰或非法碰球
        _violate:function () {
            //如果白球是最后一个静止,无法用inhole判断;
            if (myBallInHoled){
                //TODO 自由击球
                return true;
            }
            //TODO 白球第一个击中的需是目标球
            return false;
        },

        //是否有目标球进袋
        _ballIn:function () {
            this._count();
            return this.oldBallNums-this.ballNums;
        }
    };

//AI设计;
let Agent = function (targetColor) {
    this.targetBall = targetColor;
    this.ballNums = 7;
    this.violation = 0;
    this.oldBallNums = 7;
};
    Agent.prototype = {
        constructor:Agent,
        _count:function () {
            this.oldBallNums = this.ballNums;
            this.ballNums = 0;
            for (let i = 0; i < balls.length; i++) {
                if (!balls[i].inhole && balls[i].color===this.targetBall){
                    this.ballNums++;
                }
            }
        },
        _changeTarget:function () {
            this.targetBall = 1;
        },
        _violate:function() {
            if (myBallInHoled){
                //TODO 自由击球
                return true;
            }
            //TODO 白球第一个击中的需是目标球
            return false;
        },
        _ballIn:function () {
            this._count();
            return this.oldBallNums-this.ballNums;
        },

        //Agent的进球策略,提供母球的vx,vy;
        _youKnowNothingAtAll:function () {
            //初始化母球目标位置;
            //holes统计球洞的抽象位置T;
            let holes = [];
            holes.push([tbw+ballRadius,tbw+ballRadius]);
            holes.push([800/2,tbw+ballRadius]);
            holes.push([800-tbw-ballRadius,tbw+ballRadius]);
            holes.push([tbw+ballRadius,canvas.height-ballRadius-tbw]);
            holes.push([800/2,canvas.height-ballRadius-tbw]);
            holes.push([800-tbw-ballRadius,canvas.height-ballRadius-tbw]);

            //choice需要白球的击打方向vx,vy,及对该选择进行的评估,白球目标位置(xn,yn);
            let choice = [],xn,yn,xb,yb,xt,yt,x0,y0,angleCos;
            x0 = balls[0].x;
            y0 = balls[0].y;
            // 直线球和吃库球路径计算;
            for (let i = 8; i < 16; i++) {
                if (balls[i].color === this.targetBall && balls[i].inhole === false){
                    xb = balls[i].x;
                    yb = balls[i].y;
                    //对球洞进行遍历,计算母球目标位置,再计算母球运动轨迹与目标球轨迹的夹角;
                    for (let t = 0; t < 6; t++) {
                        xt = holes[t][0];
                        yt = holes[t][1];
                        // 先对BT路径检测,BT可行再计算N点;
                        if (this._routeFeasible(i,xb,yb,-1,xt,yt)){
                            let pointNCoordinate = this._myBallTarget(xb,yb,xt,yt);
                            xn = pointNCoordinate.xn;
                            yn = pointNCoordinate.yn;
                            // 1个N点对应1条直线路径和4条吃库路径;
                            //直线球NO路径判断;
                            if (this._routeFeasible(0,x0,y0,-1,xn,yn)){
                                // NO,BT向量夹角判断;
                                angleCos = this._vectorAngleCos(xn,yn,x0,y0,xb,yb,xt,yt);
                                if (angleCos < 0){
                                    // 保存母球目标位置和夹角余弦值;
                                    choice.push([xn,yn,angleCos]);
                                }
                            }
                            //对N点探索吃库路径,O1(x1,y1)是O点镜像,O2是母球在库边碰撞位置;
                            let x1,y1,x2,y2;
                            //母球对左边框碰撞;
                            y1 = y0;
                            x2 = tbw+ballRadius;
                            x1 = 2*x2-x0;
                            y2 = y1+(x2-x1)*(yn-y1)/(xn-x1);
                            if (this._routeFeasible(-1,x2,y2,-1,xn,yn) && this._routeFeasible(0,x0,y0,-1,x2,y2)){
                                angleCos = this._vectorAngleCos(xn,yn,x2,y2,xb,yb,xt,yt);
                                if (angleCos < 0){
                                    choice.push([x2,y2,angleCos]);
                                }
                            }
                            //母球对上边框碰撞;
                            x1 = x0;
                            y2 = tbw+ballRadius;
                            y1 = 2*y2-y0;
                            x2 = x1+(xn-x1)*(y2-y1)/(yn-y1);
                            if (this._routeFeasible(-1,x2,y2,-1,xn,yn) && this._routeFeasible(0,x0,y0,-1,x2,y2)){
                                angleCos = this._vectorAngleCos(xn,yn,x2,y2,xb,yb,xt,yt);
                                if (angleCos < 0){
                                    choice.push([x2,y2,angleCos]);
                                }
                            }
                            //母球对右边框碰撞;
                            y1 = y0;
                            x2 = 800-tbw-ballRadius;
                            x1 = 2*x2-x0;
                            y2 = y1+(x2-x1)*(yn-y1)/(xn-x1);
                            if (this._routeFeasible(-1,x2,y2,-1,xn,yn) && this._routeFeasible(0,x0,y0,-1,x2,y2)){
                                angleCos = this._vectorAngleCos(xn,yn,x2,y2,xb,yb,xt,yt);
                                if (angleCos < 0){
                                    choice.push([x2,y2,angleCos]);
                                }
                            }
                            //母球对下边框碰撞;
                            x1 = x0;
                            y2 = 544-tbw-ballRadius;
                            y1 = 2*y2-y0;
                            x2 = x1+(xn-x1)*(y2-y1)/(yn-y1);
                            if (this._routeFeasible(-1,x2,y2,-1,xn,yn) && this._routeFeasible(0,x0,y0,-1,x2,y2)){
                                angleCos = this._vectorAngleCos(xn,yn,x2,y2,xb,yb,xt,yt);
                                if (angleCos < 0){
                                    choice.push([x2,y2,angleCos]);
                                }
                            }
                        }

                        //翻袋打法,对给定B,T寻找4边的翻袋路径,注意边界上的球袋不处理;
                        // 球袋镜像T1(x1,y1),目标球与框碰撞位置T2(x2,y2);
                        let x1,y1,x2,y2;
                        //目标球碰左边框;
                        if (xt !== tbw+ballRadius){
                            y1 = yt;
                            x2 = tbw+ballRadius;
                            x1 = 2*x2-xt;
                            y2 = y1+(x1-x2)*(y1-yb)/(xb-x1);
                            // 先对BT2T和T2检测;
                            if (this._routeFeasible(i,xb,yb,-1,x2,y2) && this._routeFeasible(-1,xt,yt,-1,x2,y2)){
                                // 由BT2计算N点坐标;
                                let pointNCoordinate = this._myBallTarget(xb,yb,x2,y2);
                                xn = pointNCoordinate.xn;
                                yn = pointNCoordinate.yn;
                                if (this._routeFeasible(0,x0,y0,-1,xn,yn)){
                                    angleCos = this._vectorAngleCos(xn,yn,x0,y0,xb,yb,x2,y2);
                                    if (angleCos < 0){
                                        choice.push([xn,yn,angleCos]);
                                    }
                                }
                            }
                        }
                        //目标球碰上边框;
                        if (yt !== tbw+ballRadius){
                            x1 = xt;
                            y2 = tbw+ballRadius;
                            y1 = 2*y2-yt;
                            x2 = x1+(xb-x1)*(y2-y1)/(yb-y1);
                            if (this._routeFeasible(i,xb,yb,-1,x2,y2) && this._routeFeasible(-1,xt,yt,-1,x2,y2)){
                                let pointNCoordinate = this._myBallTarget(xb,yb,x2,y2);
                                xn = pointNCoordinate.xn;
                                yn = pointNCoordinate.yn;
                                if (this._routeFeasible(0,x0,y0,-1,xn,yn)){
                                    angleCos = this._vectorAngleCos(xn,yn,x0,y0,xb,yb,x2,y2);
                                    if (angleCos < 0){
                                        choice.push([xn,yn,angleCos]);
                                    }
                                }
                            }
                        }
                        //目标球碰右边框;
                        if (xt !== 800-tbw-ballRadius){
                            y1 = yt;
                            x2 = 800-tbw-ballRadius;
                            x1 = 2*x2-xt;
                            y2 = y1+(x1-x2)*(y1-yb)/(xb-x1);
                            if (this._routeFeasible(i,xb,yb,-1,x2,y2) && this._routeFeasible(-1,xt,yt,-1,x2,y2)){
                                let pointNCoordinate = this._myBallTarget(xb,yb,x2,y2);
                                xn = pointNCoordinate.xn;
                                yn = pointNCoordinate.yn;
                                if (this._routeFeasible(0,x0,y0,-1,xn,yn)){
                                    angleCos = this._vectorAngleCos(xn,yn,x0,y0,xb,yb,x2,y2);
                                    if (angleCos < 0){
                                        choice.push([xn,yn,angleCos]);
                                    }
                                }
                            }
                        }
                        //目标球碰下边框;
                        if (yt !== 544-tbw-ballRadius){
                            x1 = xt;
                            y2 = 544-tbw-ballRadius;
                            y1 = 2*y2-yt;
                            x2 = x1+(xb-x1)*(y2-y1)/(yb-y1);
                            if (this._routeFeasible(i,xb,yb,-1,x2,y2) && this._routeFeasible(-1,xt,yt,-1,x2,y2)){
                                let pointNCoordinate = this._myBallTarget(xb,yb,x2,y2);
                                xn = pointNCoordinate.xn;
                                yn = pointNCoordinate.yn;
                                if (this._routeFeasible(0,x0,y0,-1,xn,yn)){
                                    angleCos = this._vectorAngleCos(xn,yn,x0,y0,xb,yb,x2,y2);
                                    if (angleCos < 0){
                                        choice.push([xn,yn,angleCos]);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            //选择策略;
            function policySelect() {
                policyMaxPower();
            }
            policySelect();
            //大力出奇迹策略;
            function policyMaxPower() {
                let template = 0, key = 0;
                //选择最直的轨迹;
                if (choice.length===0){
                    balls[0].vx=30;
                    balls[0].vy=0;
                    balls[0].moving = true;
                }else {
                    for (let i = 0; i < choice.length; i++) {
                        if (template>choice[i][2]){
                            template = choice[i][2];
                            key = i;
                        }
                    }
                    //大力出奇迹策略;
                    if (template >= -1 && template < 0){
                        xn = choice[key][0];
                        yn = choice[key][1];
                        balls[0].vx = 30*(xn-x0)/Math.sqrt(Math.pow(xn-x0,2)+Math.pow(yn-y0,2));
                        balls[0].vy = 30*(yn-y0)/Math.sqrt(Math.pow(xn-x0,2)+Math.pow(yn-y0,2));
                        balls[0].moving = true;
                    }
                }
            }
        },
        // 根据目标球B当前位置和目标球需要到达的位置T,计算母球需要到达的位置N
        _myBallTarget:function (xb,yb,xt,yt) {
            let deltaBT = Math.sqrt(Math.pow(xt-xb,2)+Math.pow(yt-yb,2));
            let xn = xb-2*ballRadius*(xt-xb)/deltaBT;
            let yn = yb-2*ballRadius*(yt-yb)/deltaBT;
            return {xn: xn, yn: yn};
        },
        // 序号i,j的两球间路径是否有其它球阻挡;
        _routeFeasible:function (i,x1,y1,j,x2,y2) {
            for (let k = 0; k < 16; k++) {
                if (k!==i && k!==j && balls[k].inhole === false){
                    let xk = balls[k].x;
                    let yk = balls[k].y;
                    let Beta = Math.atan(Math.abs(y1-y2)/Math.abs(x1-x2));
                    if (xk > (Math.min(x1,x2)-2*ballRadius*Math.sin(Beta)) && xk < (Math.max(x1,x2)+2*ballRadius*Math.sin(Beta))
                        && yk > (Math.min(y1,y2)-2*ballRadius*Math.cos(Beta)) && yk < (Math.max(y1,y2)+2*ballRadius*Math.cos(Beta))){
                        let deltaY = y1+(xk-x1)*(y2-y1)/(x2-x1)-yk;
                        if (Math.abs(deltaY)<(2*ballRadius/Math.cos(Beta))){
                            // 若存在球k阻挡,立即返回;
                            return false;
                        }
                    }
                }
            }
            // 所有非i,j球通过检测,返回true;
            return true;
        },
        // 向量NO和BT夹角计算;
        _vectorAngleCos:function (xn,yn,x0,y0,xb,yb,xt,yt) {
            return ((x0-xn)*(xt-xb)+(y0-yn)*(yt-yb))
                /(Math.sqrt(Math.pow(x0-xn,2)+Math.pow(y0-yn,2))*Math.sqrt(Math.pow(xt-xb,2)+Math.pow(yt-yb,2)));
        }

    };

Array.prototype.foreach = function(callback){
    for(let i=0;i<this.length;i++){
        callback.apply(this[i] , [i]);
    }
};